package com.kckj.comm.util;


import com.jcraft.jsch.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
 * sftp ftp 工具类
 */
public class SftpUtil {

    private static final Logger log = LoggerFactory.getLogger(SftpUtil.class);

    public static final String TEMP_FILE_PATH = "/test";

    private String host;

    private String user;

    private String password;

    private int port;

    private Session session;

    private ChannelSftp channelSftp;

    /**
     * 构造基于密码认证的sftp对象
     * @param user
     * @param password
     * @param host
     * @param port
     */
    public SftpUtil(String user, String password, String host, int port) {
        this.user = user;
        this.password = password;
        this.host = host;
        this.port = port;
    }

    /**
     * 连接sftp服务器
     * @throws Exception
     */
    public void login() throws Exception {
        JSch jSch = new JSch();
        log.info("连接sftp服务器");
        session = jSch.getSession(user, host, port);
        session.setUserInfo(new UserInfo() {
            @Override
            public String getPassphrase() {
                return null;
            }

            @Override
            public String getPassword() {
                return null;
            }

            @Override
            public boolean promptPassword(String s) {
                return false;
            }

            @Override
            public boolean promptPassphrase(String s) {
                return false;
            }

            @Override
            public boolean promptYesNo(String s) {
                return true;
            }

            @Override
            public void showMessage(String s) {

            }
        });

        session.setPassword(password);
        session.connect();
        Channel channel = session.openChannel("sftp");
        channel.connect();
        channelSftp = (ChannelSftp) channel;
        log.info("登陆sftp服务器Success");
    }

    /**
     * 关闭sftp连接
     */
    public void logout() {
        if (channelSftp != null) {
            if (channelSftp.isConnected()){
                channelSftp.disconnect();
            }
        }
        if (session != null && session.isConnected()) {
            long time = System.currentTimeMillis();
            log.info("开始断开sftp服务器连接：{}", time);
            session.disconnect();
            log.info("已经断开sftp服务器连接：{}", time);
        }

    }

    /**
     * 判断文件是否存在
     * @param filePath
     * @param fileName
     * @return
     * @throws Exception
     */
    public boolean fileExist(String filePath, String fileName) throws Exception {
        SftpATTRS stat = null;
        try {
            channelSftp.cd(filePath);
            stat = channelSftp.stat(fileName);
        } catch (Exception e) {
        }
        boolean flag = true;
        if (stat == null) {
            flag = false;
        }

        return flag;
    }

    /**
     * 获取文件的修改时间
     * @return
     */
    public int getFileMtime(String filePath, String fileName) throws Exception {
        int fileMtime = 0;
        try {
            channelSftp.cd(filePath);
            SftpATTRS fileAttrs = channelSftp.lstat(fileName);
            fileMtime =  fileAttrs.getMTime();

        }catch (Exception e) {
        }

        return fileMtime;
    }


    /**
     * 上传文件
     * @param localPath
     * @param localFile
     * @param remotePath
     * @throws Exception
     */
    public void putFile(String localPath, String localFile, String remotePath) throws Exception {
        String remoteFile = null;
        if (remotePath != null && remotePath.trim().length() > 0) {
            try {
                channelSftp.mkdir(remotePath);
            } catch (Exception e) {
            }
            remoteFile = remotePath + "/.";
        } else {
            remoteFile = ".";
        }
        String file = null;
        if (localFile == null || localFile.trim().length() == 0) {
            file = "*";
        } else {
            file = localFile;
        }
        if (localPath != null && localPath.trim().length() > 0) {
            if (localPath.endsWith("/")) {
                file = localPath + file;
            } else {
                file = localPath + "/" + file;
            }
        }
        channelSftp.put(file, remoteFile);
    }

    public void putFile(String localPath, String remotePath) throws Exception {
        String remoteFile;
        if (remotePath != null && remotePath.trim().length() > 0) {
            try {
                channelSftp.mkdir(remotePath);
            } catch (Exception e) {
            }
            remoteFile = remotePath + "/.";
        } else {
            remoteFile = ".";
        }
        channelSftp.put(localPath, remoteFile);
    }

    /**
     * 删除文件
     * @param path
     * @return
     */
    public boolean deleteFile(String path) {
        boolean success = false;
        try {
            channelSftp.rm(path);
            log.info("删除远程文件" + path + "成功!");
            success = true;
        } catch (Exception e) {
            log.error("删除文件时有SftpException异常!", e);
            return success;
        }
        return success;
    }

    /**
     * 以流的方式上传文件
     * @param inputStream
     * @param remotePath
     * @param remoteFileName
     */
    public void putFile(InputStream inputStream, String remotePath, String remoteFileName) {
        try {
            String remoteFile;
            if (remotePath != null && remotePath.trim().length() > 0) {
                try {
                    channelSftp.mkdir(remotePath);
                } catch (Exception e) {
                }
                remoteFile = remotePath + "/" + remoteFileName;
            } else {
                throw new RuntimeException("远程服务器文件路径为空");
            }
            channelSftp.put(inputStream, remoteFile);
        } catch (Exception e) {
            log.error("put file error", e);
        }
    }

    /**
     * 调用此方法 记得关闭通道
     * @param path
     * @return
     * @throws Exception
     */
    public InputStream getInputStream(String path) throws Exception {
        InputStream inputStream = channelSftp.get(path);
        return inputStream;
    }

    // command 命令
    public String runCommand(String command) throws Exception {
        InputStream in = null;
        InputStream err = null;
        BufferedReader inReader = null;
        BufferedReader errReader = null;
        int time = 0;
        String s = null;
        boolean run = false;
        StringBuffer sb = new StringBuffer();

        Channel channel = session.openChannel("exec");
        ((ChannelExec) channel).setCommand(command);
        channel.setInputStream(null);
        ((ChannelExec) channel).setErrStream(null);
        err = ((ChannelExec) channel).getErrStream();
        in = channel.getInputStream();
        channel.connect();
        inReader = new BufferedReader(new InputStreamReader(in, "UTF-8"));
        errReader = new BufferedReader(new InputStreamReader(err, "UTF-8"));

        while (true) {
            s = errReader.readLine();
            if (s != null) {
                sb.append("error:" + s).append("\n");
            } else {
                run = true;
                break;
            }
        }
        while (true) {
            s = inReader.readLine();
            if (s != null) {
                sb.append("info:" + s).append("\n");
            } else {
                run = true;
                break;
            }
        }

        while (true) {
            if (channel.isClosed() || run) {
                break;
            }
            try {
                Thread.sleep(1000);
            } catch (Exception ee) {
            }
            if (time > 180) {
                break;
            }
            time++;
        }

        inReader.close();
        errReader.close();
        channel.disconnect();
        return sb.toString();
    }

    /**
     * 压缩生成zip文件
     * @param filePath：源文件路径(需要压缩的路径)
     * @param targetPath：解压后的路径
     * @param zipName：目标压缩文件名：a.zip
     * @return
     */
    public boolean zipFile(String filePath, String targetPath, String zipName){
        boolean flag = false;
        File resourcesFile = new File(filePath);     //源文件
        File targetFile = new File(targetPath);          //目的

        //如果目的路径不存在，则新建
        if (!resourcesFile.exists()) {
            resourcesFile.mkdir();
        }
        if (!targetFile.exists()) {
            targetFile.mkdir();
        }
        FileOutputStream outputStream = null;
        try {
            outputStream = new FileOutputStream(targetPath + "/" + zipName);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }

        ZipOutputStream out = null;
        try {
            out = new ZipOutputStream(new BufferedOutputStream(outputStream));
            if (!resourcesFile.isDirectory()) {
                log.info("压缩文件必须为整个目录");
                return false;
            }
            int BUFFER_SIZE = 1024;
            byte buff[] = new byte[BUFFER_SIZE];
            File dir = new File(filePath);
            if (!dir.isDirectory()) {
                throw new IllegalArgumentException(targetPath + " 不是一个文件夹");
            }
            File files[] = dir.listFiles();

            int fileSize = 0;
            for (int i = 0; i < files.length; i++) {
//                if (files[i].getName().indexOf(".zip") < 0) {//目录下有一个zip文件 不压缩原zip文件
                FileInputStream fi = new FileInputStream(files[i]);
                BufferedInputStream origin = new BufferedInputStream(fi);
                ZipEntry entry = new ZipEntry(files[i].getName());
                out.putNextEntry(entry);
                int count;
                while ((count = origin.read(buff)) != -1) {
                    out.write(buff, 0, count);
                }
                origin.close();
                fileSize++;
//                }
            }

            if (fileSize > 0) {
                flag = true;
            }
            log.info("ZipOutputStream 成功压缩文件的长度: " + fileSize);
        } catch (IOException e) {
            e.printStackTrace();
            log.error("压缩文件到：" + targetPath + " 时发生异常");
        } finally {
            if (out != null) {
                try {
                    out.close();
                } catch (IOException e) {
                    e.printStackTrace();
                    log.error("ZipOutputStream关闭时 发生异常");
                }
            }
            resourcesFile.delete();
            targetFile.delete();
        }
        return flag;
    }


}
